package com.gkzf.ai.module.crm.service.product.app;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gkzf.ai.framework.common.pojo.PageResult;
import com.gkzf.ai.framework.common.util.object.BeanUtils;
import com.gkzf.ai.module.crm.config.BaseService;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.admittancecondition.LiabilityVo;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.admittancecondition.OverdueRecordVo;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.admittancecondition.QueryLimitVo;
import com.gkzf.ai.module.crm.controller.admin.product.vo.product.CrmProductRespVO;
import com.gkzf.ai.module.crm.controller.admin.product.vo.productadmittancecondition.ProductAdmittanceConditionRespVO;
import com.gkzf.ai.module.crm.controller.app.product.vo.ProductDetailsRespVO;
import com.gkzf.ai.module.crm.controller.app.product.vo.ProductPageReqVO;
import com.gkzf.ai.module.crm.controller.app.product.vo.ProductRespVO;
import com.gkzf.ai.module.crm.dal.dataobject.product.CrmProductDO;
import com.gkzf.ai.module.crm.dal.mysql.product.CrmProductMapper;
import com.gkzf.ai.module.crm.dal.redis.product.CRMProductRedisDAO;
import com.gkzf.ai.module.crm.enums.DictTypeEnum;
import com.gkzf.ai.module.crm.service.creditReport.CreditReportAdmittanceConditionService;
import com.gkzf.ai.module.crm.service.product.admin.ProductAdmittanceConditionService;
import com.gkzf.ai.module.system.api.dict.DictDataApi;
import com.gkzf.ai.module.system.api.dict.dto.DictDataRespDTO;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;

import static com.gkzf.ai.module.crm.enums.ErrorCodeConstants.PRODUCT_NO_EXISTS;
import static com.gkzf.ai.module.crm.enums.ProductEnum.*;
import static com.gkzf.ai.module.crm.util.AnalysisJsonObjectUtils.*;


/**
 * CRM 产品 Service 实现类
 *
 * @author ZanGe丶
 */
@Service
@Validated
public class CrmProductAppServiceImpl extends BaseService<CrmProductDO> implements CrmProductAppService {

    @Resource(name = "crmProductMapper")
    private CrmProductMapper productMapper;

    /**
     * 准入条件
     */
    @Resource
    private ProductAdmittanceConditionService admittanceConditionService;

    /**
     * 征信
     */
    @Resource
    private CreditReportAdmittanceConditionService creditReportAdmittanceConditionService;
    /**
     * 产品缓存对象
     */
    @Resource
    private CRMProductRedisDAO crmProductRedisDAO;

    @Resource
    private CrmProductMapper crmProductMapper;

    @Resource
    private DictDataApi dictDataApi;



    /**
     * 获取App产品详情基本页
     * @param id 编号
     * @return 产品详情页
     */
    @Override
    public ProductDetailsRespVO getAppProduct(Long id) {
        super.isIdExists(id, PRODUCT_NO_EXISTS);
        ProductDetailsRespVO respVO = crmProductRedisDAO.get(id);
        if (Objects.nonNull(respVO)){
            return respVO;
        }
        CrmProductDO product = productMapper.selectById(id);
        ProductAdmittanceConditionRespVO condition = admittanceConditionService.getProductAdmittanceCondition(product.getNo());
        List<DictDataRespDTO> dictDataList = dictDataApi.getDictDataList();
        // 是否收藏

        // 产品要求
        /*
            拼接组装产品要求
         */
        // 申请人要求集合
        List<String> requestPersonConditionsList = new ArrayList<>();
        // 征信要求集合
        List<String> creditReportingPersonConditionsList = new ArrayList<>();
        Map<Predicate<ProductAdmittanceConditionRespVO>, String> conditionMap = new HashMap<>();
        // 户籍判断
        conditionMap.put(e -> StringUtils.isNotBlank(e.getBasicInfoCensusRegister()) && !Objects.equals(condition.getBasicInfoCensusRegister(),"0"),
                "仅限："+productMapper.getRegionNameByCode(condition.getBasicInfoCensusRegister())+" 常驻居民申请。");
        // 客户类型判断
        conditionMap.put(e -> StringUtils.isNotBlank(e.getBasicInfoCustomerType()),
                "适用人群："+getDictDataLabel(dictDataList, DictTypeEnum.CRM_PRODUCT_CLIENT_TYPE.getCode(),Arrays.asList(condition.getBasicInfoCustomerType().split(COMMA))));
        // 单位限制判断
        conditionMap.put(e -> StringUtils.isNotBlank(e.getBasicInfoUnitNature()),
                "您的单位需要满足："+getDictDataLabel(dictDataList, DictTypeEnum.CRM_PRODUCT_COMPANY_TYPE.getCode(),Arrays.asList(condition.getBasicInfoUnitNature().split(COMMA))));
        // 行业限制判断
        conditionMap.put(e -> StringUtils.isNotBlank(e.getBasicInfoSpecialIndustry()) && !Objects.equals(condition.getBasicInfoSpecialIndustry(),"0"),
                "禁止特殊行业,根据风控要求，以下行业从业者暂无法申请："+getDictDataLabel(dictDataList, DictTypeEnum.CRM_PRODUCT_TRADE_RESTRAINT.getCode(),Arrays.asList(condition.getBasicInfoSpecialIndustry().split(COMMA))));
        // 学历限制判断
        conditionMap.put(e -> Objects.nonNull(e.getEducationLevel()) && !Objects.equals(condition.getEducationLevel(),0),
                "要求学历："+getDictDataLabel(dictDataList, DictTypeEnum.CRM_DEGREE.getCode(),Arrays.asList(condition.getBasicInfoUnitNature().split(COMMA))));
        // 年龄判断
        conditionMap.put(e -> StringUtils.isNotBlank(e.getBasicInfoUnitNature()) ,
                getAgeRestriction(condition.getBasicInfoAgeJson()) );

        conditionMap.forEach((item,value) ->{
            if (item.test(condition)){
                requestPersonConditionsList.add(value);
            }
        });
        //征信要求
        Map<Predicate<ProductAdmittanceConditionRespVO>, String> creditMap = new LinkedHashMap<>();
        // 负债限制拼接
        creditMap.put(item -> Objects.equals(debtConditions(condition.getCreditReportLiabilityJson())[0],ONE.getCode()),debtConditions(condition.getCreditReportLiabilityJson())[1]);
        // 逾期限制拼接
        creditMap.put(item -> Objects.equals(overdueConditions(condition.getCreditReportOverdueJson())[0],ONE.getCode()),overdueConditions(condition.getCreditReportOverdueJson())[1]);
        // 查询记录限制拼接
        creditMap.put(item -> Objects.equals(queryRecordConditions(condition.getCreditReportQueryJson())[0],ONE.getCode()),queryRecordConditions(condition.getCreditReportQueryJson())[1]);
        // 社保限制拼接
        creditMap.put(item -> Objects.equals(socialSecurityConditions(condition)[0],ONE.getCode()),socialSecurityConditions(condition)[1]);
        // 公积金限制拼接
        creditMap.put(item -> Objects.equals(pensionFundConditions(condition)[0],ONE.getCode()),pensionFundConditions(condition)[1]);
        // 白户
        creditMap.put(item -> Objects.equals(noRecordConditions(condition)[0],ONE.getCode()),noRecordConditions(condition)[1]);
        // 五级分类
        creditMap.put(item -> Objects.equals(item.getCreditReportFiveLevel(),1),"五级分类正常。");
        creditMap.forEach((item,value) ->{
            if (item.test(condition)){
                creditReportingPersonConditionsList.add(value);
            }
        });
        ProductDetailsRespVO detailsRespVO = BeanUtils.toBean(product, ProductDetailsRespVO.class);
        detailsRespVO.setPersonalRequirements(requestPersonConditionsList);
        detailsRespVO.setCreditReportRequirements(creditReportingPersonConditionsList);
        //缓存对象 当编辑或者删除该产品时，删除缓存

        crmProductRedisDAO.setProductInfoById(detailsRespVO);
        return detailsRespVO;
    }

    /**
     * 组装白户情况要求
     * @param respVO 准入对象
     * @return String[] [0]:是否有要求 0/1 [1]:描述
     */
    public String[] noRecordConditions(ProductAdmittanceConditionRespVO respVO) {
        StringBuilder ageRestriction = new StringBuilder();
        AtomicInteger hasOverdue = new AtomicInteger(0);
        if (StringUtils.isNotBlank(respVO.getCreditReportWhiteType()) && !Objects.equals(respVO.getCreditReportWhiteType(),ZERO.getCode())){
            hasOverdue.set(1);
            String[] reportWhiteType = respVO.getCreditReportWhiteType().split(COMMA);
            ageRestriction.append("限制:");
            for (String item : reportWhiteType) {
                if (Objects.equals(item,"2")){
                    ageRestriction.append("小白户 ");
                }
                if (Objects.equals(item,ONE.getCode())){
                    ageRestriction.append("大白户");
                }
            }
        }
        if (hasOverdue.get() == 1) {
            return new String[]{ONE.getCode(), ageRestriction.append("。").toString()};
        }
        return new String[]{ZERO.getCode(),""};
    }



    /**
     * 组装社保情况要求
     * @param respVO 准入对象
     * @return String[] [0]:是否有要求 0/1 [1]:描述
     */
    public String[] socialSecurityConditions(ProductAdmittanceConditionRespVO respVO) {
        StringBuilder ageRestriction = new StringBuilder();
        AtomicInteger hasOverdue = new AtomicInteger(0);
        if (Objects.nonNull(respVO.getCreditReportSocialPlace())){
            hasOverdue.set(1);
            ageRestriction.append(crmProductMapper.getRegionNameByCode(respVO.getCreditReportSocialPlace()+""));
        }
        if (Objects.nonNull(respVO.getCreditReportSocialMonths())){
            hasOverdue.set(1);
            ageRestriction.append("社保缴存≥").append(respVO.getCreditReportSocialMonths()).append("个月 ");
        }
        if (Objects.nonNull(respVO.getCreditReportSocialBase())){
            hasOverdue.set(1);
            ageRestriction.append("缴存基数≥").append(respVO.getCreditReportSocialBase());
         }
        if (hasOverdue.get() == 1) {
            return new String[]{ONE.getCode(), ageRestriction.append("。").toString()};
        }
        return new String[]{ZERO.getCode(),""};
    }



    /**
     * 组装社保情况要求
     * @param respVO 社交限制json
     * @return String[] [0]:是否有要求 0/1 [1]:描述
     */
    public String[] pensionFundConditions(ProductAdmittanceConditionRespVO respVO) {
        StringBuilder ageRestriction = new StringBuilder();
        AtomicInteger hasOverdue = new AtomicInteger(0);
        if (Objects.nonNull(respVO.getCreditReportFundPlace())){
            hasOverdue.set(1);
            ageRestriction.append(crmProductMapper.getRegionNameByCode(respVO.getCreditReportFundPlace()+""));
        }
        if (Objects.nonNull(respVO.getCreditReportFundMonths())){
            hasOverdue.set(1);
            ageRestriction.append("公积金缴存≥").append(respVO.getCreditReportFundMonths()).append("个月 ");
        }
        if (Objects.nonNull(respVO.getCreditReportFundBase())){
            hasOverdue.set(1);
            ageRestriction.append("缴存基数≥").append(respVO.getCreditReportFundBase());
        }
        if (hasOverdue.get() == 1) {
            return new String[]{ONE.getCode(), ageRestriction.append("。").toString()};
        }
        return new String[]{ZERO.getCode(),""};
    }

    /**
     * 组装查询记录情况要求
     * @param queryRecordJson 负债限制json
     * @return String[] [0]:是否有要求 0/1 [1]:描述
     */
    public String[] queryRecordConditions(String queryRecordJson){
        StringBuilder debt = new StringBuilder();
        AtomicInteger hasOverdue = new AtomicInteger(0);
        creditReportAdmittanceConditionService.analysisQueryRecord(queryRecordJson, 1, queryLimitList ->{
            if (queryLimitList != null && !queryLimitList.isEmpty()){
                hasOverdue.set(1);

                for (QueryLimitVo queryLimitVo : queryLimitList) {
                    debt.append("近").append(queryLimitVo.getQueryLimitMonths()).append("个月机构查询次数").append("<").append(queryLimitVo.getQueryLimitMaxCount()).append("次").append(";");
                }
            }
        });
        creditReportAdmittanceConditionService.analysisQueryRecord(queryRecordJson, 2, queryLimitList ->{
            if (queryLimitList != null && !queryLimitList.isEmpty()){
                hasOverdue.set(1);
                for (QueryLimitVo queryLimitVo : queryLimitList) {
                    debt.append("近").append(queryLimitVo.getQueryLimitMonths()).append("个月本人查询次数").append("<").append(queryLimitVo.getQueryLimitMaxCount()).append("次").append(";");
                }
            }
        });
        if (hasOverdue.get() == 1){
            return new String[]{ONE.getCode(),"查询记录："+debt.substring(0, debt.length() - 1) + "。"};
        }
        return new String[]{ZERO.getCode(),""};
    }



    /**
     * 组装负债情况要求
     * @param liabilityJson 负债限制json
     * @return String[] [0]:是否有要求 0/1 [1]:描述
     */
    public String[] debtConditions(String liabilityJson){
        StringBuilder debt = new StringBuilder();
        AtomicInteger hasOverdue = new AtomicInteger(0);
        if (StringUtils.isNotBlank(liabilityJson)) {
            List<LiabilityVo> liabilityList = JSON.parseObject(liabilityJson, new TypeReference<>() {});
            if (!liabilityList.isEmpty()){
                hasOverdue.set(1);
                debt.append("负债情况: 当前");
                for (LiabilityVo liabilityVo : liabilityList) {
                    String monthsDescription = getString(liabilityVo);
                    debt.append(monthsDescription).append("<").append(liabilityVo.getLiabilityRequirementAmount()).append(";");
                }
            }
        }
        if (hasOverdue.get() == 1){
            return new String[]{ONE.getCode(),debt.substring(0, debt.length() - 1) + "。"};
        }
        return new String[]{ZERO.getCode(),""};
    }




    /**
     * 获取负债情况描述
     * @param liabilityVo 负债情况对象
     * @return  负债类型对应描述
     */
    private static String getString(LiabilityVo liabilityVo) {
        String monthsDescription = "";
        switch (liabilityVo.getLiabilityRequirementType()){
            case 1 ->monthsDescription = "非银行机构账户数（未结清）";
            case 2 ->monthsDescription = "非银行机构负债总额（未结清）";
            case 3 ->monthsDescription = "信用卡近6个月平均使用率";
            case 4 ->monthsDescription = "信用卡当前使用率";
            case 5 ->monthsDescription = "信用贷款总额";
            case 6 ->monthsDescription = "信用贷款机构数";
            default -> {}
        }
        return monthsDescription;
    }

    /**
     * 组装逾期记录征信要求
     * @param overdueJson 逾期限制 json
     * @return String[] [0]:是否有要求 0/1 [1]:描述
     */
    public String[] overdueConditions(String overdueJson) {
        // 默认无要求
        StringBuilder overdue = new StringBuilder();
        AtomicInteger hasOverdue = new AtomicInteger(0);
        if (StringUtils.isNotBlank(overdueJson)) {
            Map<String, List<OverdueRecordVo>> mapOverdue = JSON.parseObject(overdueJson, new TypeReference<>() {});
            if (mapOverdue.containsKey(SUMMARY.getCode())) {
                List<OverdueRecordVo> overdueRecordVos = mapOverdue.get(SUMMARY.getCode());
                if (!overdueRecordVos.isEmpty()){
                    hasOverdue.set(1);
                    /*
                     * 信用卡逾期记录
                     */
                    overdue.append("所有账户：");
                    overdueRecord(overdueRecordVos, overdue);
                }
                /*
                 * 合计逾期记录
                 */
                overdueRecord(overdueRecordVos, overdue);
            }
            if (mapOverdue.containsKey(LOANS)) {
                List<OverdueRecordVo> overdueRecordVos = mapOverdue.get(LOANS);
                if (!overdueRecordVos.isEmpty()){
                    hasOverdue.set(1);
                    /*
                     * 贷款逾期记录
                     */
                    overdue.append("贷款逾期：");
                    overdueRecord(overdueRecordVos, overdue);
                }
            }
            if (mapOverdue.containsKey(CREDITCARD)) {
                List<OverdueRecordVo> overdueRecordVos = mapOverdue.get(CREDITCARD);
                if (!overdueRecordVos.isEmpty()){
                    hasOverdue.set(1);
                    /*
                     * 信用卡逾期记录
                     */
                    overdue.append("信用卡逾期：");
                    overdueRecord(overdueRecordVos, overdue);
                }
            }
        }
        if (hasOverdue.get() == 1){
            return new String[]{ONE.getCode(),overdue.substring(0, overdue.length() - 1) + "。"};
        }
        return new String[]{ZERO.getCode(), ""};
    }


    /**
     * 拼接逾期要求
     * @param overdueRecordVos 逾期详情集合
     * @param loanOverdue 存储逾期情况字符串
     */
    private static void overdueRecord(List<OverdueRecordVo> overdueRecordVos, StringBuilder loanOverdue) {
        overdueRecordVos.forEach(overdueRecordVo -> {
            //逾期次数
            if (StringUtils.isNotBlank(overdueRecordVo.getOverUeRecordMonths())){
                extracted(loanOverdue, new String[]{overdueRecordVo.getOverUeRecordMonths().split(COMMA)[0], "逾期次数", overdueRecordVo.getOverUeRecordMonths().split(COMMA)[1]});
            }
            //最大连续次数
            if (StringUtils.isNotBlank(overdueRecordVo.getContinuousOverdueMonths())){
                extracted(loanOverdue, new String[]{overdueRecordVo.getContinuousOverdueMonths().split(COMMA)[0], "最大连续次数", overdueRecordVo.getContinuousOverdueMonths().split(COMMA)[1]});
            }
            //最大连续次数
            if (StringUtils.isNotBlank(overdueRecordVo.getMaxMonthsOverdueMonths())){
                extracted(loanOverdue, new String[]{overdueRecordVo.getMaxMonthsOverdueMonths().split(COMMA)[0], "最长逾期月数", overdueRecordVo.getMaxMonthsOverdueMonths().split(COMMA)[1]});
            }
            //最大连续次数
            if (StringUtils.isNotBlank(overdueRecordVo.getMaxMonthsOverdueAmountMonths())){
                extracted(loanOverdue, new String[]{overdueRecordVo.getMaxMonthsOverdueAmountMonths().split(COMMA)[0], "最高逾期金额", overdueRecordVo.getMaxMonthsOverdueAmountMonths().split(COMMA)[1]});
            }
        });
    }

    private static void extracted(StringBuilder loanOverdue, String[] monthsDescription) {
        if (null == monthsDescription || monthsDescription.length == 0){
            return;
        }
        switch (monthsDescription[0]) {
            case "1" -> monthsDescription[0] = "近1个月";
            case "6" -> monthsDescription[0] = "近6个月逾期";
            case "12" -> monthsDescription[0] = "近12个月逾期";
            case "24" -> monthsDescription[0] = "近24个月逾期";
            case "60" -> monthsDescription[0] = "近60个月逾期";
            default -> {
            }
        }
        // 有一个不为0 则拼接这组数据

        loanOverdue.append(monthsDescription[0]).append(monthsDescription[1]).append("< ").append(monthsDescription[2]).append(";");
    }

    /**
     * 获取字典数据
     * @param dictDataList  字典 数据
     * @param type  字典类型
     * @param value 字典值
     * @return 字典数据
     */
    private String getDictDataLabel(List<DictDataRespDTO> dictDataList,String type, List<String> value) {

        StringBuilder builder = new StringBuilder();
        List<DictDataRespDTO> dictTypeList = dictDataList.stream().filter(item -> item.getDictType().equals(type)).toList();
        dictTypeList.forEach(item ->{
            if (value.contains(item.getValue())){
                builder.append(item.getLabel()).append(",");
            }
        });
        if (StringUtils.isNotBlank(builder)){
           return builder.substring(0, builder.length() - 1) + "。";
        }
        return builder.toString();
    }

    /**
     *  组装年龄情况
     * @param ageRestrictionJson 年龄要求json
     * @return 年龄限制
     */
    private String getAgeRestriction(String ageRestrictionJson){
        JSONObject ageJson = JSON.parseObject(ageRestrictionJson,new TypeReference<>(){});
        String ageRestriction = "";
        if (ageJson.containsKey(ONE.getCode())){
            JSONObject o = (JSONObject)ageJson.get(ONE.getCode());
            if (o.containsKey(MALE.getCode())){
                JSONObject male = o.getJSONObject(MALE.getCode());
                Object max = male.get(MAX.getCode());
                Object min = male.get(MIN.getCode());
                ageRestriction += MALE.getValue()+" "+min+"-"+max+"周岁\n";
            }
            if (o.containsKey(FEMALE.getCode())){
                JSONObject female = o.getJSONObject(FEMALE.getCode());
                Object max = female.get(MAX.getCode());
                Object min = female.get(MIN.getCode());
                ageRestriction += FEMALE.getValue()+" "+min+"-"+max+"周岁。";
            }
        }else {
            JSONObject age = JSON.parseObject(ageRestrictionJson,new TypeReference<>(){});
            JSONObject o = (JSONObject)age.get("0");
            Object max = o.get(MAX.getCode());
            Object min = o.get(MIN.getCode());
            ageRestriction += "年龄"+" "+min+"-"+max+"周岁。";
        }
        return ageRestriction;
    }



    /**
     * 获取小程序产品分页
     *  小程序产品分页 分为3个类型 精选推荐  信用贷  抵押贷
     *   精选推荐根据创建时间排序
     *   信用贷根据额度排序
     *   抵押贷根据利率排序
     * @param pageReqVO 分页查询
     * @return 返回列表集合
     */
    @Override
    public ProductRespVO getAppProductPage(ProductPageReqVO pageReqVO) {
        // 获取精选推荐产品列表
        IPage<CrmProductDO> iPage = new Page<>(pageReqVO.getPageNo(),pageReqVO.getPageSize());
        pageReqVO.setIsRecommendation(1);
        // 产品精选推荐列表
        IPage<CrmProductRespVO> productRecommendationPage = productMapper.selectProductAppPage(iPage, pageReqVO);
        PageResult<CrmProductRespVO> recommendationPage = new PageResult<>(productRecommendationPage.getRecords(), productRecommendationPage.getTotal());
        // 获取信用贷产品分页
        pageReqVO.setIsRecommendation(0);
        pageReqVO.setLoanType("0");
        // 排序根据最高额度排序
        pageReqVO.setSortMethod("DESC");
        pageReqVO.setSortField("label");
        IPage<CrmProductRespVO> productCreditPage = productMapper.selectProductAppPage(iPage, pageReqVO);
        PageResult<CrmProductRespVO> creditPage = new PageResult<>(productCreditPage.getRecords(), productCreditPage.getTotal());
        // 获取信用贷产品分页
        pageReqVO.setIsRecommendation(0);
        pageReqVO.setLoanType("1");
        // 排序根据最高额度排序
        pageReqVO.setSortMethod("ASC");
        pageReqVO.setSortField("label");
        IPage<CrmProductRespVO> productMortgagePage = productMapper.selectProductAppPage(iPage, pageReqVO);
        PageResult<CrmProductRespVO> mortgagePage = new PageResult<>(productMortgagePage.getRecords(), productMortgagePage.getTotal());
        return ProductRespVO.builder().creditPage(creditPage).recommendationPage(recommendationPage).mortgagePage(mortgagePage).build();
    }

    /**
     * 获取小程序产品列表
     * @param productIdList 产品id列表
     * @return 产品列表
     */
    @Override
    public List<ProductDetailsRespVO> getAppProductList(List<Long> productIdList) {
        List<CrmProductDO> inList = super.getInList(CrmProductDO::getId, productIdList);
        return BeanUtils.toBean(inList, ProductDetailsRespVO.class);
    }
}
